#use Test::More tests => 118;
use Test::More qw(no_plan);

BEGIN {
use_ok( 'Firepear::Carrot::DOM' );
}

# setup
my $d;
my $attrs;
my $tiefile = './t/corpus/test';

# bad 'new' calls
$d = Firepear::Carrot::DOM->new;
is ($d->status, 901, 'no tmpfile given');
$d = Firepear::Carrot::DOM->new( file => 1 );
is ($d->status, 902, 'no docinfo given');
$d = Firepear::Carrot::DOM->new( file => 1, root => {'foo', 'bar'});
is ($d->status, 903, 'docinfo not arrayref');
$d = Firepear::Carrot::DOM->new( root => ['foo', 'bar'],
				 file => 'foo/bar' );
is ($d->status, 905, 'tiefile linkage error');

# a good 'new' call
$d = Firepear::Carrot::DOM->new( file => $tiefile,
				 root => ['author', 'Random Q. Hacker',
                                          'date', '2006-09-02'] );
is (ref $d, 'Firepear::Carrot::DOM', 'ok');
is ($d->status, 0, 'ok');

# validtype tests
is ($d->validtype('TRIGGER'),  1, 'ok');
is ($d->validtype('TAG'),      1, 'ok');
is ($d->validtype('TEXT'),     1, 'ok');
is ($d->validtype('VERBATIM'), 1, 'ok');
is ($d->validtype('FOO'),      0, 'invalid node type');
is ($d->validtype,         undef, 'no node type passed');

# node add failures
is ($d->add, undef, 'add failure 1');
is ($d->status,  101, 'type argument not given');
is ($d->status(0), 0, 'clearing status');
is ($d->add({ type => 'FOO' }), undef, 'addnode failure 2');
is ($d->status, 102, 'bad type argument');
$d->status(0);
is ($d->add({ type    => 'TEXT',
              content => 'foo',
              parent  => 6000 }), undef, 'addnode failure 13');
is ($d->status, 106, 'bad parent node argument passed');
$d->status(0);
is ($d->add({ type    => 'TRIGGER',
              element => 'section' }), undef, 'ad failure (no finfo)');
is ($d->status, 107, 'no fileinfo passed');
$d->status(0);
is ($d->add({ type  => 'TAG', finfo => [1, 1],
              attrs => 'foo' }), undef, 'addnode failure 3');
is ($d->status, 401, 'attrs arg is not arrayref');
$d->status(0);
is ($d->add({ type  => 'TEXT', finfo => [1, 1],
              attrs => ['foo', 2] }), undef, 'addnode failure 4');
is ($d->status, 402, 'attrs arg passed for TEXT node');
$d->status(0);
is ($d->add({ type => 'TEXT', finfo => [1, 1],
             element => 'foo' }), undef, 'addnode failure 5');
is ($d->status, 402, 'element arg passed for TEXT node');
$d->status(0);
is ($d->add({ type => 'TEXT', finfo => [1, 1], content => 'foo',
              refid => 'foo' }), undef, 'addnode failure 5');
is ($d->status, 402, 'id arg passed for TEXT node');
$d->status(0);
is ($d->add({ type    => 'TRIGGER', finfo => [1, 1],
              content => 'foo' }), undef, 'addnode failure 6');
is ($d->status, 403, 'content arg passed for TRIG node');
$d->status(0);
is ($d->add({ type    => 'TAG', finfo => [1, 1],
              content => 'foo' }), undef, 'addnode failure 7');
is ($d->status, 403, 'content arg passed for TAG node');
$d->status(0);
is ($d->add({ type    => 'VERBATIM', finfo => [1, 1],
              content => 'foo' }), undef, 'addnode failure 8');
is ($d->status, 403, 'content arg passed for VERB node');
$d->status(0);
is ($d->add({ type  => 'VERBATIM', finfo => [1, 1],
              attrs => ['foo', 2] }), undef, 'addnode failure 9');
is ($d->status, 105, 'no element name for VERB node');
$d->status(0);
is ($d->add({ type  => 'TRIGGER', finfo => [1, 1],
              attrs => ['foo', 2] }), undef, 'addnode failure 10');
is ($d->status, 105, 'no element name for TRIGGER node');
$d->status(0);
is ($d->add({ type  => 'TAG', finfo => [1, 1],
              attrs => ['foo', 2] }), undef, 'addnode failure 11');
is ($d->status, 105, 'no element name for TAG node');
$d->status(0);
is ($d->add({ type => 'TEXT', finfo => [1, 1] }), undef, 'addnode failure 12');
is ($d->status, 104, 'no content for TEXT node');

# addnode successes
$d = Firepear::Carrot::DOM->new( file => $tiefile,
				 root => ['author', 'Random Q. Hacker',
                                          'date', '2006-09-02'] );
is ($d->add({ type => 'TEXT', finfo => [0, 1],
              content => 'First node' }), 1, 'First successfully added node' );
is ($d->status, 0, 'Ok');
is ($d->add({ type => 'TEXT', finfo => [2, 30],
              content => 'Nodus Secundus' }),
    2, 'Second successfully added node');
is ($d->{dom}{tree}[2]{parent}, 0, 'parent is root');
is ($d->curnode, 0, 'still pointing at root');
is ($d->status, 0, 'Ok');
# peek inside DOM
is_deeply ( $d->{dom}{tree}[0]{cids},
	    [1, 2], 'Root cids list is as expected');
is ($d->{dom}{tree}[1]{parent}, 0, 'First nodes parent is root');
is ($d->{dom}{tree}[2]{parent}, 0, 'Second nodes parent is root');
is ($d->{dom}{tree}[1]{finfo}[0], 0, 'Fileinfo');
is ($d->{dom}{tree}[1]{finfo}[1], 1, 'Fileinfo');
is ($d->{dom}{tree}[2]{finfo}[0], 2, 'Fileinfo');
is ($d->{dom}{tree}[2]{finfo}[1], 30, 'Fileinfo');
is ($d->{dom}{text}[0],     'First node', 'node 1 content');
is ($d->{dom}{text}[1], 'Nodus Secundus', 'node 2 content');
## now run same tests through method calls
is_deeply ($d->nodechildren,
	  [1, 2], 'Root cids list is as expected' );
is_deeply ($d->nodechildren(0),
	  [1, 2], 'Root cids list is as expected' );
is ($d->nodeparent,    0, 'root should have self as parent');
is ($d->nodeparent(1), 0, 'Node 1 parent is root');
is ($d->nodeparent(2), 0, 'Node 2 parent is root');
is ($d->nodecontent(1),     'First node', 'node 1 content');
is ($d->nodecontent(2), 'Nodus Secundus', 'node 2 content');
is_deeply ($d->nodefileinfo(2),
	   [2, 30], 'Node 2 finfo is as expected' );
is_deeply ($d->nodechildren(1),
	  [0], 'Node 1 cids list is as expected' );
is_deeply ($d->nodechildren(2),
	  [1], 'Node 2 cids list is as expected' );
is ($d->{dom}{ptr}, 0, 'still pointing at root/docinfo');
is ($d->nodecontent, undef, 'root has no content');
is ($d->status,        302, 'no content on requested node');
$d->status(0);
is ($d->nodeattrs(1), undef, 'no attributes');
is ($d->status,         304, 'code for no attribs on requested node');
$d->status(0);

# attributes and modification thereof
$attrs = $d->nodeattrs;
is ($attrs->{author}, 'Random Q. Hacker', 'root author attrib');
is ($attrs->{date},         '2006-09-02', 'root date attrib');
$d->nodeattrs(0,['author','Ramona Cartwright', 'author', 'foo', 'bar', 'baz']);
$attrs = $d->nodeattrs;
is (ref $attrs->{author}, 'ARRAY', 'author attribute is now a listref');
is ($attrs->{author}[0],  'Random Q. Hacker', 'original author');
is ($attrs->{author}[1], 'Ramona Cartwright', 'new author');
is ($attrs->{bar}, 'baz', 'new scalar attrib');

## add some things that aren't TEXT nodes
is ($d->add({ type    => 'TRIGGER',
              element => 'section',
              finfo   => [2, 2], refid => 'sec1' }),
    3, 'Add a section trigger');
is ($d->status,      0, 'Ok');
is ($d->{dom}{tree}[3]{refid}, 'sec1', 'id was set properly');
is ($d->{dom}{ids}{sec1}, 1, 'and stowed in dom ids hash for uniqueness');
is ($d->nodeid(3), 'sec1', 'id was set properly');
is ($d->nodechildren(3), undef, 'no kids');
is ($d->status,    303, 'No kids to get');
$d->status(0);

# check element names
is ($d->nodename, 'document', 'root node ok');
is ($d->nodename(3), 'section', 'just set this');
is ($d->nodename(2), undef, 'TEXT nodes dont have names');
is ($d->status, 305, 'no name on TEXT');
$d->status(0);

# jmp testing
is ($d->jmp(3), 3, 'Move pointer to new section node');
is ($d->curnode, 3, 'Pointer moved');
is ($d->jmp('parent'), 0, 'special form jumps up tree');
is ($d->curnode, 0, 'Pointer moved');
is ($d->jmp, 0, 'NOOP');
is ($d->jmp('q'), undef, 'jmpnode arg wrong type');
is ($d->status,     201, 'jmpnode arg wrong type');
$d->status(0);
is ($d->jmp(399), undef, 'jmpnode arg out of bounds');
is ($d->status,     201, 'jmpnode arg out of bounds');
$d->status(0);
$d->jmp(3);

is ($d->add({ type => 'TEXT', content => 'Section Title', finfo => [1, 2] }),
    4, 'Give section a title string');
is ($d->add({ type => 'TAG', element => 'index',
              finfo => [1, 3], refid => 'idx',
              attrs   => [ 'ref', 'idx', 'word', 'foo', 'word', 'bar' ] }),
    5, 'Add a index tag with complex attrs');
is ($d->status, 0, 'Ok');
$attrs = $d->nodeattrs(5);
is ($d->status, 0, 'Ok');
is ($attrs->{ref},     'idx', 'simple attr');
is ($attrs->{word}[0], 'foo', 'complex attr');
is ($attrs->{word}[1], 'bar', 'complex attr');
is ($d->{dom}{ids}{idx}, 1, 'refid has been set');

# add node with explicit parent
$d->jmp(1);
is ($d->add({ type    => 'TEXT', content => 'foo', finfo => [1, 4],
              parent  => 5 }), 6, 'add node with declared parent');
is ($d->status, 0, 'ok');

# id-related failures
$d->jmp(5);
is ($d->add({ type => 'TAG', element => 'index', finfo => [1, 3],
              refid => 'idx' }),
    undef, 'dupe id');
is ($d->status, 108, 'dupe id');

# detach -- should automatically be in delete mode due to error
is ($#{ $d->{dom}{tree} }, 6, 'nodecount before detach');
$d->detach;

## misc bad calls
$d->status(0);
is ($d->nodeattrs(399),    undef, 'getattrs nonexistant node');
is ($d->status,              301, 'getattrs nonexistant node');
$d->status(0);
is ($d->nodecontent(399),  undef, 'getcontent nonexistant node');
is ($d->status,              301, 'getcontent nonexistant node');
$d->status(0);
is ($d->nodeparent(399),   undef, 'getparent nonexistant node');
is ($d->status,              301, 'getparent nonexistant node');
$d->status(0);
is ($d->nodechildren(399), undef, 'getchildren nonexistant node');
is ($d->status,              301, 'getchildren nonexistant node');


